#pragma once
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <string.h>
#include "usermanager.hpp"
#include "msgqueue.hpp"
#include "chatMsg.hpp"

#define TCPPORT 30001
#define THREADCOUNT 10

using std::cout;
using std::endl;

struct Msg{
  Msg() {
    sockfd = -1;
    memset(buf, '\0', sizeof(buf)/sizeof(buf[0]));
  }
  int sockfd;
  char buf[1024];
};

class ChatServer{
public:
  ChatServer() {
    tcp_socket_ = -1;
    tcp_port_ = TCPPORT;
    um_ = NULL;
    epofd_ = -1;
    thread_count_ = THREADCOUNT;
    send_que_ = NULL;
    ready_sockfd_que_ = NULL;
    recv_que_ = NULL;
  }

  ~ChatServer() {

  }
  
  //初始化资源
  int InitCharServer(uint16_t tcp_port = TCPPORT, int thread_count = THREADCOUNT) {
    tcp_port_ = tcp_port;
    thread_count_ = thread_count;
    tcp_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (tcp_socket_ < 0) {
      std::cout << "socket failed" << std::endl; 
      return -1;
    }
    //端口重用
    int opt = -1;
    setsockopt(tcp_socket_, SOL_SOCKET,SO_REUSEADDR, &opt, sizeof(opt));

    //绑定地址信息
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(tcp_port_);
    addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    int b_ret = bind(tcp_socket_, (struct sockaddr*)&addr, sizeof(addr));
    if (b_ret < 0) {
      perror("bind");
      std::cout << "bind failed" << std::endl; 
      return -1;
    }
    //监听
    int l_ret = listen(tcp_socket_, 1024);
    if (l_ret < 0) {
      std::cout << "listen failed" << std::endl; 
      return -1;
    }

    //初始化epoll
    epofd_ = epoll_create(1);
    if (epofd_ < 0) {
      std::cout << "epoll_create failed" << std::endl; 
      return -1;
    }
    
    //初始化用户管理
    um_ = new UserManager();
    if (um_ == NULL) {
      return -1;
    }
    if (um_->InitUserManager() == false) {
      return -1;
    }

    //初始化发送队列
    send_que_ = new MsgQueue<ChatMsg>();
    if (send_que_ == NULL) {
      return -1;
    }

    //初始化就绪队列
    ready_sockfd_que_ = new MsgQueue<int>();
    if (ready_sockfd_que_ == NULL) {
      return -1;
    }

    recv_que_ = new MsgQueue<ChatMsg>();
    if (recv_que_ == NULL) {
      return -1;
    }
    return 0;

  }

  //创建各种线程
  int StartCharServer() {
    //1.创建epoll等待线程
    pthread_t tid;
    int ret = pthread_create(&tid, NULL, epoll_wait_start, (void*)this);
    if (ret < 0) {
      return -1;
    }
    //2.创建接收线程
    ret = pthread_create(&tid, NULL, recv_msg_start, (void*)this);
    if (ret < 0) {
      return -1;
    }
    
    //3.创建发送线程
    ret = pthread_create(&tid, NULL, send_msg_start, (void*)this);
    if (ret < 0) {
      return -1;
    }
    //4.创建工作线程
    for (int i = 0; i < THREADCOUNT; i++) {

    pthread_create(&tid, NULL, deal_start, (void*)this);
    }
    //主线程循环等待新链接,将新连接放到epoll中
  while(1) {
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    int new_sockfd = accept(tcp_socket_, (struct sockaddr*)&addr, &len);
    if (new_sockfd < 0) {
      continue;
    }

    struct epoll_event ee;
    ee.events = EPOLLIN;
    ee.data.fd = new_sockfd;
    std::cout << "new_sockfd" << std::endl;
    epoll_ctl(epofd_, EPOLL_CTL_ADD, new_sockfd, &ee);

    }
      return 1;
  }

  static void* epoll_wait_start(void* msg) {
    pthread_detach(pthread_self());
    ChatServer* cs = (ChatServer*)msg;
      
    while (1) {
      struct epoll_event eearr[10];
     int ret = epoll_wait(cs->epofd_, eearr, sizeof(eearr)/sizeof(eearr[0]), -1);
     if (ret < 0) {
       continue;
     }
     
     //接收正常
     //约定,最长可以接收65535个字节
     for (int i = 0; i < ret; i++) {
      char buf[65535] = {0};
      int sockfd = eearr[i].data.fd;
      int recv_s = recv(sockfd, buf, sizeof(buf) - 1, 0);
      if (recv_s < 0) {
       //接收失败 
       continue;
      }
      else if (recv_s == 0) {
        //对方把连接关闭了
        epoll_ctl(cs->epofd_, EPOLL_CTL_DEL, sockfd, NULL);
        close(sockfd);
        cs->um_->SetUserOffLine(sockfd);
        continue;
      }
        //接收成功
        string mmsg;
        mmsg.assign(buf, strlen(buf));

        ChatMsg cm;
        cm.PraseChatMsg(sockfd, mmsg);
        cs->recv_que_->push(cm);
     }
    }
    return NULL;
  }

  static void* recv_msg_start(void* msg) {
    pthread_detach(pthread_self());
    ChatServer* cs = (ChatServer*)msg;

    while (1) {
   sleep(1);
    }

  }
  


  static void* send_msg_start(void* msg) {
    pthread_detach(pthread_self());
    ChatServer* cs = (ChatServer*)msg;

    while (1) {
      //从队列中拿数据
       ChatMsg cm;
      cs->send_que_->pop(&cm);
      string mmsg;
      cm.GetMsg(&mmsg);
      
      //发送数据
      send(cm.sockfd_, mmsg.c_str(), mmsg.size(), 0);

    }
    return NULL;
  }

  static void* deal_start(void* arg) {
    pthread_detach(pthread_self());
    ChatServer* cs = (ChatServer*)arg;

    while (1) {
      //1.获取消息
      ChatMsg cm;
      cs->recv_que_->pop(&cm);
      //判断消息类型
      int msg_type = cm.msg_type_;
      switch(msg_type) {
        case Register : {
              cs->DealRegister(cm);
              break;
        }
        case Login : {
              cs->DealLogin(cm);
              break;
        }
        case AddFriend : {
              cs->DealAddFriend(cm);
              break;
        }
        case PushAddFriendMsg_Resp : {
              cs->DealAddFriendResp(cm);
              break;
        }
        case SendMsg : {
              cs->DealSendMsg(cm);
              break;
        }
        case GetFriendMsg : {
              cs->GetAllFriendInfo(cm);
              break;
        }
        default : {
              break;
        }

      }
    }
    return NULL;
  }

  void DealRegister(ChatMsg& cm) {
    //1.获取注册信息
    string nickname = cm.GetValue("nickname");
    string school = cm.GetValue("school");
    string telnum = cm.GetValue("telnum");
    string passwd = cm.GetValue("passwd");
    //2.调用用户管理系统中的注册接口
    int userid = -1;
    //std::cout << "nickname" <<nickname << "school" <<school << "telnum" <<telnum << "passwd" <<passwd << std::endl;
    int ret = um_->DealRegister(nickname, school, telnum, passwd, &userid);
    //3.回复应答
    std::cout << "ret:" << ret <<std::endl; 
    cm.clear();
    cm.msg_type_ = Register_Resp;
    if (ret < 0) {
      cm.reply_status_ = REGISTER_FAILED;
    }
    else {
      cm.reply_status_ = REGISTER_SUCCESS;
    }
    cm.userid_ = userid;
    send_que_->push(cm);
  } 

  void DealLogin(ChatMsg& cm) {
    //获取数据
    string telnum = cm.GetValue("telnum");
    string passwd = cm.GetValue("passwd");
    //调用用户管理模块的代码
    int ret = um_->DealLogin(telnum, passwd, cm.sockfd_);
   cout << "你到这里了么" << endl; 
    //回复应答
    cm.clear();
    cm.msg_type_ = Login_Resp;
    if (ret < 0) {
      cm.reply_status_ = LOGIN_FAILED;
    }
    else {
      cm.reply_status_ = LOGIN_SUCCESS;
    }
    cm.userid_ = ret;
    this->send_que_->push(cm);
  }

  void DealAddFriend(ChatMsg& cm) {
    //1.获取被添加方的号码
    string telnum = cm.GetValue("telnum");
    //添加方的userid
    int adduid = cm.userid_;
    cm.clear();
    //2.查询被添加方是否是登录状态
    UserInfo be_add_ui;
    int ret = um_->IsLogin(telnum, &be_add_ui);
    if (ret == -1) {
      //用户不存在
      cm.json_msg_ = AddFriend_Resp;
      cm.reply_status_ = ADDFRIEND_FAILED;
      cm.SetValue("content", "user not exist, please check friend tel num");
      send_que_->push(cm);
      return;
    }
    else if (ret == OFFLINE) {
      //把消息缓存下来,等对方上线再发送
      return;
    }
    //对方在线
    UserInfo add_ui;
    um_->GetUserInfo(adduid, &add_ui);
    cm.sockfd_ = be_add_ui.tcp_socket_;
    cm.msg_type_ = PushAddFriendMsg;
    cm.SetValue("adder_nickname", add_ui.nickname_);
    cm.SetValue("adder_school", add_ui.school_);
    cm.SetValue("adder_userid", add_ui.userid_);
    cout << cm.json_msg_ << endl;
    send_que_->push(cm);
  }

  void DealAddFriendResp(ChatMsg& cm) {
    //1.获取双方用户信息
    int reply_status = cm.reply_status_;
    //获取被添加方的用户信息
    int be_add_u = cm.userid_;
    UserInfo be_uif;
    um_->GetUserInfo(be_add_u, &be_uif);

    //获取添加方的用户信息,通过应答,获取添加方的userid
    int add_ui = atoi(cm.GetValue("userid").c_str());
    UserInfo uif;
    um_->GetUserInfo(add_ui, &uif);

    //2.判断相应状态
    cm.clear();
    cm.sockfd_ = uif.tcp_socket_;
    cm.msg_type_ = AddFriend_Resp;
    if (reply_status == ADDFRIEND_SUCCESS) {
      cm.reply_status_ = ADDFRIEND_FAILED;
      string content = "add user" + be_uif.nickname_ + " failed";
      cm.SetValue("content", content);
    }
    else {
      cm.reply_status_ = ADDFRIEND_SUCCESS;
      string content = "add user" + be_uif.nickname_ + " success";
      cm.SetValue("content", content);
      cm.SetValue("peer_nick_name", be_uif.nickname_);
      cm.SetValue("peer_school", be_uif.school_);
      cm.SetValue("peer_userid", be_uif.userid_);

      //向用户管理模块当中维护好友信息
      um_->SetFriend(add_ui, be_add_u);
    }

    if (uif.user_status_ == OFFLINE) {
      //消息队列放在缓冲队列中,择机发送
    }
    //3.给添加方回复相应
    send_que_->push(cm);

  }

  void GetAllFriendInfo(ChatMsg& cm) {
    //1.从用户管理模块获取好友信息
    int userid = cm.userid_;

    cm.clear();
    std::vector<int> fri;
    bool ret = um_->GetFriends(userid, &fri);
    if (ret == false) {
      cm.reply_status_ = GETFRIEND_FAILED;
    }
    else {
      cm.reply_status_ = GETFRIEND_SUNCCESS;
    }
    cm.msg_type_ = GetFriendMsg_Resp;

    for (size_t i = 0; i < fri.size(); i++) {
      UserInfo temp;
      um_->GetUserInfo(fri[i], &temp);

      Json::Value val;
      val["nickname"] = temp.nickname_;
      val["school"] = temp.school_;
      val["userid"] = temp.userid_;

      cm.json_msg_.append(val);
    }
    send_que_->push(cm);
  }
  
  void DealSendMsg(ChatMsg& cm) {
    int send_id = cm.userid_;
    int recv_id = cm.json_msg_["recvmsgid"].asInt();
    string send_msg = cm.json_msg_["msg"].asString();
    cm.clear();

    UserInfo recv_ui;
    bool ret = um_->GetUserInfo(recv_id, &recv_ui);
    //用户不存在,发送消息失败
    //用户不在线,缓存消息,等上线再发
    if (ret == false || recv_ui.user_status_ == OFFLINE) {
      cm.msg_type_ = SendMsg_Resp;
      cm.reply_status_ = SENDMAS_FAILED;
      send_que_->push(cm);
      return;
    }

    cm.clear();
    cm.msg_type_ = SendMsg_Resp;
    cm.reply_status_ = SENDMSG_SUCCESS;
    send_que_->push(cm);

    //获取发送方的用户信息
    UserInfo send_ui;
    um_->GetUserInfo(send_id, &send_ui);

    cm.clear();
    cm.msg_type_ = PushMsg;
    cm.sockfd_ = recv_ui.tcp_socket_;
    cm.SetValue("peer_nickname", send_ui.nickname_);
    cm.SetValue("peer_school", send_ui.school_);
    cm.SetValue("peer_userid", send_ui.userid_);
    cm.SetValue("peer_msg", send_msg);
    send_que_->push(cm);
  }
private:
  //侦听套接字
  int tcp_socket_;
  //侦听端口
  int tcp_port_;

  //用户管理模块的指针,管理用户
  UserManager* um_;

  //epoll操作句柄
  int epofd_;

  //工作线程的数量
  int thread_count_;
  
  //需要发送的消息队列
  MsgQueue<ChatMsg>* send_que_;

  //已经就绪的文件描述符队列
  MsgQueue<int>* ready_sockfd_que_;

  //接收队列
  MsgQueue<ChatMsg>* recv_que_;
};
